﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using HQS.TokenInterpolation.Core;

namespace HQS.TokenInterpolation
{
    public class Parser
    {
        public static bool ValidateTemplate(string template)
        {
            try
            {
                var document = new Scanner(template);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static Result Parse(string template, IDataSourcesVisitor runtimeContext)
        {
            Result result = null;
            Stopwatch processingWatch = Stopwatch.StartNew();
            if (runtimeContext == null)
            {
                throw new ArgumentNullException("runtimeContext");
            }

            if (template == null)
            {
                throw new ArgumentNullException("template");
            }

            try
            {
                var tokenWithValues = new Dictionary<string, TokenRuntimeValue>();
                var document = new Scanner(template);
                var sb = new StringBuilder(document.SanitizeText());

                foreach (IVisitable token in document.Tokens.OrderByDescending(f => f.AllowNestingTokens ? 1 : 0))
                {
                    TokenRuntimeValue tokenRuntimeValue = token.Accept(runtimeContext);
                    tokenWithValues[token.Name] = tokenRuntimeValue;
                    if (tokenRuntimeValue != null)
                    {
                        sb.Replace(token.OriginalText,
                            tokenRuntimeValue.Resolved == false ? token.IfErrorUse : tokenRuntimeValue.Value);
                    }
                }

                result = new Result(tokenWithValues, sb.ToString());
                result.SetParsingTime(processingWatch);
            }
            finally
            {
                processingWatch.Stop();
            }

            return result;
        }
    }
}